import { observable, action, set } from 'mobx';
import imStore, { IM } from './im';
import authStore from '@/cross/stores/auth';
import { $toast } from '@/cross/utils';
import util from '../../utils/im';
import uuid from '../../utils/uuid';
import { IMessage, IMessageBase } from '../../types';
import { IImGeo, IMessageFile, IScene } from '../../types/base';
import { IImError } from '../../types/error';

class Actions {

  @observable imStore = imStore;

  /**
   * 生成临时消息
   */
  generateFakeMsg = (options: {
    scene: IMessage['scene'];
    to: string;
    type: IMessage['type'];
    url: string;
    name?: string;
    size?: number;
    width?: number;
    height?: number;
    duration?: number;
    pendingUrl?: string;
  }): IMessage | void => {
    const {
      scene, to, type, url, width, height, name, size, duration, pendingUrl
    } = options;
    let baseMsg: IMessageBase = {
      sessionId: scene + '-' + to,
      scene,
      from: imStore.user?.account,
      to,
      flow: 'out',
      idClientFake: uuid(),
      status: 'sending',
      time: new Date().getTime(),
    };
    if (type === 'text') {
      let msg: IMessage = {
        ...baseMsg,
        type: 'text',
        text: ''
      };
      return IM.mim?.formatMessage(msg);
    }
    if (type === 'image') {
      if (!name || !size || !width || !height) return;
      let msg: IMessage = {
        ...baseMsg,
        type: 'image',
        file: {
          name,
          size,
          url,
          w: width,
          h: height,
          pendingUrl: pendingUrl || url
        }
      };
      return IM.mim?.formatMessage(msg);
    }
    if (type === 'video') {
      if (!name || !width || !height || !duration) return;
      let msg: IMessage = {
        ...baseMsg,
        type: 'video',
        file: {
          name,
          size: size || 0,
          url,
          w: width,
          h: height,
          dur: duration,
          pendingUrl
        }
      };
      return IM.mim?.formatMessage(msg);
    }
  }


  @action
  appendSessionMsg = (msg: IMessage) => {
    console.log('[appendSessionMsg] ', msg);
    const { currentSessionId, currentSessionMsgs } = imStore;
    const { sessionId } = msg;
    const tempMsgs: IMessage[] = [];
    if (sessionId === currentSessionId) {
      const msgLen = currentSessionMsgs.length;
      if (msgLen > 0) {
        const lastMsgTime = currentSessionMsgs[0].time || 0;
        if (((msg.time || 0) - lastMsgTime) > 1000 * 60 * 5) {
          tempMsgs.push({
            type: 'timeTag',
            text: util.formatDate(msg.time, false),
            time: msg.time,
            key: uuid(),
          });
        }
      } else {
        tempMsgs.push({
          type: 'timeTag',
          time: msg.time,
          text: util.formatDate(msg.time, false),
          key: uuid(),
        });
      }
      tempMsgs.push(msg);
      console.log('[tempMsgs] ', tempMsgs);
      imStore.currentSessionMsgs = tempMsgs.concat(imStore.currentSessionMsgs.slice());
    }
  }

  // 替换消息列表消息，如消息撤回
  @action replaceSessionMsg = ({
    sessionId,
    idClient,
    idClientFake,
    msg
  }: {
    sessionId: string;
    idClient: string;
    idClientFake?: string;
    msg: IMessage;
  }) => {
    const { currentSessionId, currentSessionMsgs } = imStore;
    if (sessionId === currentSessionId) {
      const tempMsgs = currentSessionMsgs || [];
      if (tempMsgs.length > 0) {
        const lastMsgIndex = tempMsgs.length - 1;
        for (let i = lastMsgIndex; i >= 0; i -= 1) {
          const currMsg = tempMsgs[i];
          if (idClientFake && idClientFake === currMsg.idClientFake) {
            tempMsgs.splice(i, 1, msg);
            break;
          } else if (idClient && idClient === currMsg.idClient) {
            tempMsgs.splice(i, 1, msg);
            break;
          }
        }
        imStore.currentSessionMsgs = util.simpleClone(tempMsgs);
      }
    }
  }

  @action
  updateSessionMsg = (msg: IMessage) => {
    const { currentSessionId, currentSessionMsgs } = imStore;
    const { sessionId, idClient, idClientFake } = msg;
    if (sessionId === currentSessionId) {
      const msgLen = currentSessionMsgs.length;
      if (msgLen > 0) {
        for (let i = msgLen - 1; i >= 0; i -= 1) {
          if (idClientFake) {
            if (currentSessionMsgs[i].idClientFake === idClientFake) {
              set(currentSessionMsgs[i], msg);
              imStore.currentSessionMsgs = currentSessionMsgs.concat([]);
              break;
            }
          } else if (idClient) {
            if (currentSessionMsgs[i].idClient === idClient) {
              set(currentSessionMsgs[i], msg);
              imStore.currentSessionMsgs = currentSessionMsgs.concat([]);
              break;
            }
          }
        }
      }
    }
  }

  @action
  resendTextMsg = (message: IMessage) => {
    console.log('准备重发消息：', message);
    if (IM.mim) {
      IM.mim?.resendMsg({
        msg: message,
        done: (error, newMsg, data) => {
          console.log('重发消息回调：', error, newMsg, data);
          if (error) {
            // Alert.alert('提示', error.message, [
            //   { text: '确认' },
            // ]);
            newMsg.status = 'fail';
          }
          if (newMsg.sessionId && newMsg.idClient) {
            this.replaceSessionMsg({
              sessionId: newMsg.sessionId,
              idClient: newMsg.idClient,
              msg: newMsg,
            });
          }
        },
      });
    }
  };

  @action
  sendTextMsg = ({
    scene, to, text,
  }: { scene: IScene; to: string; text: string; }) => {
    if (IM.mim) {
      const msg = IM.mim?.sendText({
        scene,
        to,
        text,
        pushPayload: JSON.stringify({
          isImMessage: 1,
          scene,
          to: imStore.user?.account,
          action: 'IM_MESSAGE'
        }),
        done: (error, newMsg) => {
          // console.log('[error] ', error)
          if (error) {
            if (error.code === 7101) {
              newMsg.status = 'fail';
              return $toast('您被对方拉黑 无法发送消息')
            } else {
              // Alert.alert('提示', error.message, [
              //   { text: '确认' },
              // ]);
            }
          }
          if (newMsg.sessionId && newMsg.idClient) {
            this.replaceSessionMsg({
              sessionId: newMsg.sessionId,
              idClient: newMsg.idClient,
              msg: newMsg,
            });
          }
        },
      });
      this.appendSessionMsg(msg);
    }
  };

  @action
  sendGeoMsg = ({
    scene,
    to,
    geo
  }: {
    scene: IScene;
    to: string;
    geo: IImGeo;
  }) => {
    if (IM.mim) {
      const msg = IM.mim?.sendGeo({
        scene,
        to,
        geo: {
          title: geo.title,
          lat: geo.lat,
          lng: geo.lng
        },
        pushPayload: JSON.stringify({
          isImMessage: 1,
          scene,
          to: imStore.user?.account,
          action: 'IM_MESSAGE'
        }),
        done: (error, newMsg) => {
          if (error) {
            if (error.code === 7101) {
              newMsg.status = 'fail';
              return $toast('您被对方拉黑 无法发送消息')
            } else {
              // Alert.alert('提示', error.message, [
              //   { text: '确认' },
              // ]);
            }
          }
          if (newMsg.sessionId && newMsg.idClient) {
            this.replaceSessionMsg({
              sessionId: newMsg.sessionId,
              idClient: newMsg.idClient,
              msg: newMsg,
            });
          }
        }
      })
      this.appendSessionMsg(msg);
    }
  }

  @action
  sendCustomMsg = ({ scene, to, text, content }: {
    scene: IScene;
    to: string;
    text: string;
    content: object;
  }) => {
    if (IM.mim) {
      const msg = IM.mim?.sendCustomMsg({
        scene,
        to,
        text,
        content,
        pushPayload: JSON.stringify({
          isImMessage: 1,
          scene,
          to: imStore.user?.account,
          action: 'IM_MESSAGE'
        }),
        done: (error, newMsg) => {
          if (error) {
            if (error.code === 7101) {
              newMsg.status = 'fail';
              return $toast('您被对方拉黑 无法发送消息')
            } else {
              // Alert.alert('提示', error.message, [
              //   { text: '确认' },
              // ]);
            }
          }
          this.replaceSessionMsg({
            sessionId: newMsg.sessionId || '',
            idClient: newMsg.idClient || '',
            msg: newMsg,
          });
        },
      });
      this.appendSessionMsg(msg);
    }
  };

  @action
  sendImageMsg = ({
    type,
    scene,
    to,
    filePath,
    width,
    height,
    size,
    duration,
    md5,
    // pendingUrl: `data:${response.type};base64,${response.data}`,
    callback,
  }: {
    type: 'image' | 'video';
    scene: IScene;
    to: string;
    filePath: string;
    width: number;
    height: number;
    size: number;
    duration?: number;
    md5: string;
    callback: () => void;
  }) => {
    if (IM.mim) {
      // 本地的图片先显示了，并转菊花
      const prevMsg = this.generateFakeMsg({
        type,
        scene,
        to,
        url: filePath,
        width,
        height,
        size,
        duration,
        name: type
      });
      console.log('[prevMsg] ', prevMsg);
      if (prevMsg) this.appendSessionMsg(prevMsg);
      if (callback instanceof Function) {
        callback();
      }
      if (!IM.mim) return;
      IM.mim?.previewFile({
        type,
        filePath,
        uploadprogress(obj) {
          console.log(`文件总大小: ${obj.total}bytes`);
          console.log(`已经上传的大小: ${obj.loaded}bytes`);
          console.log(`上传进度: ${obj.percentage}`);
          console.log(`上传进度文本: ${obj.percentageText}`);
        },
        done: (error, { name, url, ext }) => {
          const file = {
            name,
            url,
            w: width,
            h: height,
            md5,
            size,
            ext,
          };
          if (!error && IM.mim) {
            const msg = IM.mim?.sendFile({
              type,
              scene,
              to,
              file,
              pushPayload: JSON.stringify({
                isImMessage: 1,
                scene,
                to: imStore.user?.account,
                action: 'IM_MESSAGE'
              }),
              done: (error, newMsg) => {
                if (error) {
                  if (error.code === 7101) {
                    newMsg.status = 'fail';
                    return $toast('您被对方拉黑 无法发送消息')
                  } else {
                    // Alert.alert('提示', error.message, [
                    //   { text: '确认' },
                    // ]);
                  }
                }
                if (newMsg.type === 'image' && prevMsg && prevMsg.type === 'image' && prevMsg.file) {
                  newMsg.file.pendingUrl = prevMsg.file.pendingUrl;
                }
                if (newMsg.type === 'video' && prevMsg && prevMsg.type === 'video' && prevMsg.file) {
                  newMsg.file.pendingUrl = prevMsg.file.pendingUrl;
                }
                this.replaceSessionMsg({
                  sessionId: newMsg.sessionId || '',
                  idClient: newMsg.idClient || '',
                  msg: {
                    ...newMsg,
                    // 保留idClientFake用于仍然显示本地图片非网络图片
                    idClientFake: prevMsg ? prevMsg.idClientFake : ''
                  },
                });
              },
            });
            // 替换本地假消息
            const tempMsg = util.simpleClone(msg);
            // tempMsg.file.pendingUrl = prevMsg.file.pendingUrl;
            this.replaceSessionMsg({
              sessionId: msg.sessionId || '',
              idClient: msg.idClient || '',
              idClientFake: prevMsg ? prevMsg.idClientFake : undefined,
              msg: tempMsg,
            });
            if (callback instanceof Function) {
              callback();
            }
          }
        },
      });
    }
  };

  @action
  sendAudioMsg = ({
    scene,
    to,
    filePath,
    dur,
    size,
    md5,
    // pendingUrl: `data:${response.type};base64,${response.data}`,
    callback,
  }: {
    scene: IScene;
    to: string;
    filePath: string;
    dur: number;
    size: number;
    md5: string;
    callback: () => void;
  }) => {
    if (IM.mim) {
      IM.mim?.previewFile({
        type: 'audio',
        filePath,
        uploadprogress(obj) {
          console.log(`文件总大小: ${obj.total}bytes`);
          console.log(`已经上传的大小: ${obj.loaded}bytes`);
          console.log(`上传进度: ${obj.percentage}`);
          console.log(`上传进度文本: ${obj.percentageText}`);
        },
        done: (error, { name, url }) => { 
          const file: IMessageFile = {
            name,
            url,
            dur,
            md5,
            size,
            ext: 'aac',
          };
          if (!error && IM.mim) {
            const msg = IM.mim?.sendFile({
              type: 'audio',
              scene,
              to,
              file,
              pushPayload: JSON.stringify({
                isImMessage: 1,
                scene,
                to: imStore.user?.account,
                action: 'IM_MESSAGE'
              }),
              done: (err, newMsg) => {
                if (err) {
                  newMsg.status = 'fail';
                }
                // newMsg.file.pendingUrl = prevMsg.file.pendingUrl;
                this.replaceSessionMsg({
                  sessionId: newMsg.sessionId || '',
                  idClient: newMsg.idClient || '',
                  msg: newMsg,
                });
              },
            });
            this.appendSessionMsg(msg);
            if (callback instanceof Function) {
              callback();
            }
          }
        },
      });
    }
  };

  @action sendMsgReceipt = ({
    msg
  }: { msg: IMessage }) => {
    IM.mim?.sendMsgReceipt({
      msg,
      done: function sendMsgReceiptDone(error) {
        if (error) {
          // Alert.alert('提示', error.message, [
          //   { text: '确认' },
          // ]);
        }
      },
    });
  }

  @action onBackoutMsg = (error: object, msg: IMessage) => {
    // console.log(msg.to, msg.sessionId);
    if (error) {
      console.log(error);
      return;
    }
    let tip = '';
    let toAccount = '';
    if (msg.from === imStore.user?.account) {
      tip = '你撤回了一条消息';
      toAccount = msg.to || '';
    } else {
      const user = imStore.usersMap[msg.from || ''];
      if (user) {
        tip = `${util.getFriendAlias(user)}撤回了一条消息`;
      } else {
        tip = '对方撤回了一条消息';
      }
      toAccount = msg.from || '';
    }
    IM.mim?.sendTipMsg({
      isLocal: true,
      scene: msg.scene,
      to: toAccount,
      tip,
      time: msg.time || 0,
      done: (tipErr, tipMsg) => {
        if (tipErr) {
          console.log(tipErr);
          return;
        }
        const idClient = msg.deletedIdClient || msg.idClient;
        const { sessionId } = msg;
        if (sessionId && idClient) {
          this.replaceSessionMsg({
            sessionId,
            idClient,
            msg: tipMsg,
          });
        }
      },
    });
  };

  @action backoutMsg = (msg: IMessage) => {
    IM.mim?.deleteMsg({
      msg,
      done: (error) => {
        // Alert.alert('提示', '撤回一条消息', [
        //   { text: '确认' },
        // ]);
        this.onBackoutMsg(error, msg);
      },
    });
  }

  @action deleteMsg = (msg: IMessage, index: number) => {
    imStore.currentSessionMsgs.splice(index, 1)
    IM.mim?.deleteLocalMsg({
      msg,
      done: (error, result) => {
        console.log('[deleteMsg] ', error, result)
      },
    });
  }

  @action getLocalMsgs =(sessionId: string, options: {
    reset: boolean;
    end?: number;
    done?: (res: { haveNext: boolean }) => void;
  }) => {
    const { reset, end, done } = options;
    let [scene, to] = sessionId.split('-') as [IScene, string];
    let pageSize = 20
    IM.mim?.getLocalMsgs({
      scene,
      to,
      sessionId,
      limit: pageSize,
      end,
      desc: true,
      done: (err, obj) => {
        if (!err) {
          const tempMsgs: IMessage[] = [];
          if (sessionId === imStore.currentSessionId) {
            let lastMsgTime = 0;
            // 对原数组反向排序并插入 TimeTag
            obj.msgs = obj.msgs.sort((a, b) => (b.time || 0) - (a.time || 0));
            obj.msgs.forEach((msg) => {
              if (((msg.time || 0) - lastMsgTime) > 1000 * 60 * 5) {
                lastMsgTime = msg.time || 0;
                tempMsgs.push({
                  type: 'timeTag',
                  time: msg.time,
                  text: util.formatDate(msg.time, false),
                  key: uuid(),
                });
              }
              tempMsgs.push(msg);
            });
            if (reset) {
              imStore.currentSessionMsgs = tempMsgs;
              console.log('currentSessionMsgs: ', imStore.currentSessionMsgs);
            } else {
              imStore.currentSessionMsgs = imStore.currentSessionMsgs.concat(tempMsgs)
            }
          }
        }
        if (done instanceof Function) {
          done({
            haveNext: (!err && obj.msgs) && obj.msgs.length >= pageSize
          });
        }
      },
    });
  }

  @action
  deleteLocalMsgs = ({
    scene, to, done
  }: {
    scene: string;
    to: string;
    done: (err: IImError) => void;
  }) => {
    IM.mim?.deleteLocalMsgsBySession({
      scene,
      to,
      done: (error) => {
        imStore.currentSessionMsgs = [];
        if (done instanceof Function) {
          done(error);
        }
      },
    });
  }

  @action
  getHistoryMsgs = ({
    scene, to, endTime, done,
  }: {
    scene: IScene;
    to: string;
    endTime: number;
    done: (msgs: IMessage[]) => void;
  }) => {
    IM.mim?.getHistoryMsgs({
      scene,
      to,
      endTime,
      reverse: false,
      asc: true,
      limit: 10,
      done(error, obj) {
        if (error) {
          // Alert.alert('提示', error.message, [
          //   { text: '确认' },
          // ]);
          return;
        }
        if (done instanceof Function) {
          done(obj.msgs);
        }
      },
    });
  }

  @action
  clearSysMsgs = () => {
    imStore.sysmsgs = [];
  }
}

export default new Actions();
